Loading Component dynamically in Angular
In this tutorial, we shall see how to dynamically switch between two components inside a template in angular.
Create an angular project
First, lets create an angular application using the following angular cli command.
ng new angular-dynamic-components
Create Components in the angular project
Next, lets create two components. One will the HomeComponent and the other one will be ContactComponent.
ng g c home
ng g c contact
Create a service to query components by name
Next, we shall create a service which will hold the reference to these components. Create a service using the following angular cli command.
ng g s services/component-instance
Next, open the ComponentInstanceService
and modify the code as below.
import { Injectable } from '@angular/core';
import { HomeComponent } from '../home/home.component';
import { ContactComponent } from '../contact/contact.component';
@Injectable({
providedIn: 'root'
})
export class ComponentInstanceService {
componentInstances: Map<string, any> = new Map();
constructor() {
this.setComponent('home', HomeComponent);
this.setComponent('contact', ContactComponent);
}
setComponent(name: string, component: any): void {
this.componentInstances.set(name, component);
}
getComponent(name: string) {
return this.componentInstances.get(name);
}
}
Here, we have imported the two components. Then we have created a variable componentInstances of type Map
. This service will contain two functions setComponent()
and getComponent()
function.
The setComponent()
function takes 2 arguments. The first argument is the string
and the second argument is the Component
. Then we will set the Component with name as the key
to the Map
variable componentInstances
.
The getComponent()
function which gets the key
as parameter and returns the Component
associated with it.
In the constructor
of the service we will add the HomeComponent
with home
as its key
and ContactComponent
with contact
as the key
by calling the setComponent()
function.
Add FormsModule to AppModule
Next, open the app.module.ts
file and add the reference to the FormsModule
and add it the the imports array. Also add the HomeComponent
and ContactComponent
to the entryComponents
array.
import { BrowserModule, HammerModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AngularMaterialModule } from './angular-material/angular-material.module';
import { HomeComponent } from './home/home.component';
import { ContactComponent } from './contact/contact.component';
@NgModule({
declarations: [
AppComponent,
HomeComponent,
ContactComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
BrowserAnimationsModule,
AngularMaterialModule,
HammerModule
],
providers: [],
entryComponents: [HomeComponent, ContactComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
Next, Open the app.component.html file and modify the code as below.
<select [(ngModel)]='componentName' (change)='loadComponent(componentName)'>
<option value='home'>Home</option>
<option value='contact'>Contact</option>
</select>
<ng-template #mainContent>
</ng-template>
Here, we have a dropdown which holds two values Home and Contact which is binded to the Model componentName on selecting any value. We also have a ng-template with the name mainContent to which the components will be replaced depending on the value selected in the dropdown.
Update AppComponent to load components dynamically
Now open the app.component.ts file and modify the code as below.
import { Component, OnInit, ViewChild, ViewContainerRef, ComponentFactoryResolver } from '@angular/core';
import { ComponentInstanceService } from './services/component-instance.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
componentName: string;
@ViewChild('mainContent', { read: ViewContainerRef, static: true }) mainContent: ViewContainerRef;
constructor(private componentInstance: ComponentInstanceService, private resolver: ComponentFactoryResolver) { }
ngOnInit(): void {
}
loadComponent(name: string) {
console.log('Function has been called', name);
this.mainContent.clear();
const component = this.componentInstance.getComponent(name);
const componentFactory = this.resolver.resolveComponentFactory(component);
this.mainContent.createComponent(componentFactory);
}
}
The ViewChild
we will refer the template as the ViewContainerRef
.
Inject the ComponentInstanceService
and ComponentFactoryResolver
to the constructor.
Everytime when the dropdown is changed we will call the loadComponent
with its name. Now we pass the name which is the key to the getComponent()
function and get the Component associated with it.
Then, the ComponentFactoryResolver
is used to resolve a ComponentFactory
for the specific component. Then to add the component to the template, you call createComponent()
on ViewContainerRef
.
Run the angular project
Now, run your application with the following command.
ng serve --o